class WebSocketUtil {
    constructor(url, config = {}) {
        this.socket = new WebSocket(url);
        this.config = config;
        this.messageHandlers = [];
        this.heartbeatTimer = null;
        this.heartbeatInterval = config.heartbeatInterval || 30000; // 默认 30 秒

        this._setupSocketEvents();
    }

    /** 初始化 WebSocket 事件 */
    _setupSocketEvents() {
        this.socket.onopen = () => {
            this._resetHeartbeat();
            this.config.onOpen?.();
        };

        this.socket.onerror = (err) => {
            this.config.onError?.(err);
        };

        this.socket.onclose = () => {
            this._clearHeartbeat();
            this.config.onClose?.();
        };

        this.socket.onmessage = (e) => {
            this._resetHeartbeat();
            this._handleMessage(e.data);
        };
    }

    /** 处理接收到的消息 */
    _handleMessage(data) {
        const reader = new FileReader();
        reader.onload = () => {
            const str = reader.result;
            const hexArray = [...str].map(c => c.charCodeAt(0).toString(16).padStart(2, '0'));
            const type = hexArray[3];
            if (type === '00') return; // 心跳包响应
            if (type === '03') {
                console.log('收到消息:', str)
                const length = parseInt(hexArray[1] + hexArray[2], 16);
                const payload = hexArray.slice(4, 3 + length).join('');
                const jsonStr = this._hexToString(payload);
                const message = JSON.parse(jsonStr || '{}');

                if (message?.data) {
                    const parsedData = JSON.parse(message.data);
                    this.messageHandlers.forEach(handler => handler(parsedData));
                }
            }
        };
        reader.readAsText(new Blob([data]), 'utf-8');
    }

    /** 添加消息处理器 */
    addMessageHandler(handler) {
        this.messageHandlers.push(handler);
    }

    /** 发送心跳 */
    _sendHeartbeat() {
        this._sendHex('6800020000'); // 简化版心跳
        this._resetHeartbeat();
    }

    /** 启动或重置心跳 */
    _resetHeartbeat() {
        this._clearHeartbeat();
        this.heartbeatTimer = setTimeout(() => this._sendHeartbeat(), this.heartbeatInterval);
    }

    /** 清除心跳定时器 */
    _clearHeartbeat() {
        clearTimeout(this.heartbeatTimer);
        this.heartbeatTimer = null;
    }

    /** 发送绑定用户消息 */
    sendBindMessage(userId) {
        this._sendJson({ key: userId, type: 1 }, '01');
    }

    /** 发送 WebRTC 消息 */
    sendMessage(targetUserId, message, messageType = '03') {
        this._sendJson({
            key: targetUserId,
            type: 2,
            data: JSON.stringify(message)
        }, messageType);
    }

    /** 将 JSON 数据封装为十六进制格式发送 */
    _sendJson(obj, type) {
        const hexBody = this._stringToHex(obj);
        const msg = this._wrapHexMessage(hexBody, type);
        this._sendHex(msg);
    }

    /** 发送十六进制字符串消息 */
    _sendHex(hexStr) {
        const buffer = this._hexToBuffer(hexStr);
        this.socket.send(buffer);
    }

    /** 关闭连接 */
    close() {
        this._clearHeartbeat();
        this.socket.close();
    }

    // -------------------- 工具方法 --------------------

    /** 将字符串转为十六进制 */
    _stringToHex(str) {
        try {
            const encoder = new TextEncoder('utf-8');
            const bytes = encoder.encode(str);
            return Array.from(bytes)
                .map(b => b.toString(16).padStart(2, '0'))
                .join('');
        } catch (e) {
            console.error('字符串转十六进制错误:', e);
            return '';
        }
    }

    /** 将十六进制字符串转为 UTF-8 字符串 */
    _hexToString(hex) {
        const bytes = new Uint8Array(hex.length / 2);
        for (let i = 0; i < hex.length; i += 2) {
            bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);
        }
        return new TextDecoder('utf-8').decode(bytes);
    }

    /** 封装消息头（含长度、类型） */
    _wrapHexMessage(dataHex, type) {
        const length = dataHex.length / 2 + 1;
        const lenHigh = (length >> 8).toString(16).padStart(2, '0');
        const lenLow = (length & 0xff).toString(16).padStart(2, '0');
        return `68${lenHigh}${lenLow}${type}${dataHex}`;
    }

    /** 十六进制字符串转 ArrayBuffer */
    _hexToBuffer(hex) {
        const buffer = new Uint8Array(hex.length / 2);
        for (let i = 0; i < hex.length; i += 2) {
            buffer[i / 2] = parseInt(hex.slice(i, i + 2), 16);
        }
        return buffer.buffer;
    }
}
